package org.qh.common.core.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import lombok.experimental.UtilityClass;
import org.qh.common.core.utils.collection.CollectionUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Bean 拷贝工具类，基于 Hutool BeanUtil 并添加缓存优化
 * 相比原生 BeanUtil 提供更好的性能
 *
 * @see cn.hutool.core.bean.BeanUtil
 */
@UtilityClass
public class DDDCopyUtils {
    /**
     * 缓存 CopyOptions 配置，避免重复创建
     */
    private final Map<String, CopyOptions> copyOptionsCache = new ConcurrentHashMap<>(128);

    /**
     * 缓存空对象实例，避免重复反射创建
     */
    private final Map<Class<?>, Object> emptyInstanceCache = new ConcurrentHashMap<>(64);

    /**
     * 获取默认的 CopyOptions 配置（带缓存）
     *
     * @param ignoreError 是否忽略错误
     * @return CopyOptions 实例
     */
    private CopyOptions getCopyOptions(boolean ignoreError) {
        String key = Boolean.toString(ignoreError);
        return copyOptionsCache.computeIfAbsent(key, k -> CopyOptions.create()
            .setIgnoreError(ignoreError)
            .setIgnoreNullValue(true));
    }

    /**
     * 创建目标对象的空实例（带缓存）
     *
     * @param target 目标类型
     * @param <T> 目标类型
     * @return 目标对象实例
     */
    private <T> T createEmptyInstance(Class<T> target) {
        try {
            @SuppressWarnings("unchecked")
            T instance = (T) emptyInstanceCache.computeIfAbsent(target, clazz -> {
                try {
                    return clazz.getDeclaredConstructor().newInstance();
                } catch (Exception e) {
                    throw new RuntimeException("创建对象实例失败: " + clazz.getName(), e);
                }
            });
            // 返回新的实例，避免缓存对象被污染
            return BeanUtil.copyProperties(instance, target);
        } catch (Exception e) {
            throw new RuntimeException("拷贝空实例失败: " + target.getName(), e);
        }
    }

    /**
     * 将一个对象拷贝到另一个对象
     *
     * @param source 源对象
     * @param target 目标对象的类型
     * @param <T> 目标类型
     * @return 目标对象
     */
    public <T> T copy(Object source, Class<T> target) {
        return copy(source, target, true);
    }

    /**
     * 将一个对象拷贝到另一个对象
     *
     * @param source 源对象
     * @param target 目标对象的类型
     * @param ignoreError 是否忽略拷贝过程中的错误
     * @param <T> 目标类型
     * @return 目标对象
     */
    public <T> T copy(Object source, Class<T> target, boolean ignoreError) {
        if (source == null) {
            return null;
        }

        try {
            T targetObject = createEmptyInstance(target);
            CopyOptions copyOptions = getCopyOptions(ignoreError);
            BeanUtil.copyProperties(source, targetObject, copyOptions);
            return targetObject;
        } catch (Exception e) {
            if (ignoreError) {
                return createEmptyInstance(target);
            }
            throw new RuntimeException("拷贝对象失败: " + target.getName(), e);
        }
    }

    /**
     * 拷贝列表中的每个元素
     *
     * @param listSource 源列表
     * @param target     目标对象的类型
     * @param <S>        源类型
     * @param <T>        目标类型
     * @return 目标类型的列表
     */
    public <S, T> List<T> copy(List<S> listSource, Class<T> target) {
        return copy(listSource, target, true);
    }

    /**
     * 拷贝列表中的每个元素
     *
     * @param listSource 源列表
     * @param target     目标对象的类型
     * @param ignoreError 是否忽略拷贝过程中的错误
     * @param <S>        源类型
     * @param <T>        目标类型
     * @return 目标类型的列表
     */
    public <S, T> List<T> copy(List<S> listSource, Class<T> target, boolean ignoreError) {
        if (listSource == null) {
            return Collections.emptyList();
        }

        if (listSource.isEmpty()) {
            return new ArrayList<>();
        }

        return CollectionUtils.convertList(listSource, s -> copy(s, target, ignoreError));
    }

    /**
     * 拷贝数组中的每个元素
     *
     * @param arraySource 源数组
     * @param target      目标对象的类型
     * @param <S>         源类型
     * @param <T>         目标类型
     * @return 目标类型的列表
     */
    public <S, T> List<T> copy(S[] arraySource, Class<T> target) {
        return copy(arraySource, target, true);
    }

    /**
     * 拷贝数组中的每个元素
     *
     * @param arraySource 源数组
     * @param target      目标对象的类型
     * @param ignoreError 是否忽略拷贝过程中的错误
     * @param <S>         源类型
     * @param <T>         目标类型
     * @return 目标类型的列表
     */
    public <S, T> List<T> copy(S[] arraySource, Class<T> target, boolean ignoreError) {
        if (arraySource == null) {
            return Collections.emptyList();
        }

        return copy(Arrays.asList(arraySource), target, ignoreError);
    }

    /**
     * 清空缓存（用于内存敏感的场景）
     */
    public void clearCache() {
        copyOptionsCache.clear();
        emptyInstanceCache.clear();
    }

    /**
     * 获取缓存统计信息（用于监控和调试）
     *
     * @return 缓存统计信息
     */
    public Map<String, Integer> getCacheStats() {
        Map<String, Integer> stats = new HashMap<>();
        stats.put("copyOptionsCacheSize", copyOptionsCache.size());
        stats.put("emptyInstanceCacheSize", emptyInstanceCache.size());
        return stats;
    }
}
